Repository navigation
Conversation
- Replace PackagePayload.AddVersion with AddPackageVersionRequestBody
- Move package name from body to URL: POST /cluster/package/{name}/versions
- Replace delete command pattern with DELETE /cluster/package/{name}/versions/{version}
- Replace refresh command with POST /cluster/package/{name}/refresh
- Update errPath in testAPI from /details[0]/errorMessages[0] to /msg
- Remove all add.pkg assignments (pkg now lives in URL path)
- Replace add.pkg references in verifyComponent() with literal package name strings
- Update import: remove PackagePayload, add AddPackageVersionRequestBody (sorted)
Co-authored-by: Copilot <[email protected]>
Co-authored-by: epugh <[email protected]>
…sponse.error field Co-authored-by: epugh <[email protected]>
Co-authored-by: epugh <[email protected]>
Co-authored-by: epugh <[email protected]>
|
Is there a JIRA ticket associated with this change @epugh? |
No, because I viewed it as "just a refactoring and no one will notice....", and that I was hoping there were no debates that would require a JIRA to hash out! |
| authors: | ||
| - name: Eric Pugh | ||
| links: | ||
| - name: PR#4178 |
There was a problem hiding this comment.
[0] Probably worth having a JIRA reference for this guy, even if it's just a tie-back to one of the v2 umbrella tickets? It's changing APIs and stuff, so worth tracking in more than just the PR description I'd imagine.
| public int hashCode() { | ||
| return Objects.hash(version); | ||
| } | ||
| final var request = |
There was a problem hiding this comment.
[Q] Is there a reason you're not using the auto-generated SolrJ type here? We should have one now that the API is JAX-RS!
If this was an intentional decision made to prevent scope-creep, I'm fine with that. Just making sure it's not oversight.
There was a problem hiding this comment.
so many places to update... I suspect in the future we need to do a "Check each GSR for fitness" check ;-)
There was a problem hiding this comment.
Like I said, I think not doing these bits in the same PR is a totally valid choice. I don't want to add extra steps that'd apply to all these PRs. But since the lines were changed in this PR already I wanted to check that it was an intentional choice is all 🤷
…kageapi-to-jax-rs
Rename PackageAPI to ClusterPackage to follow naming pattern of other V2 apis.
Add test, revamp description.
|
@gerlowskija I think I am ready for another review. I renamed |
|
@gerlowskija I reopened this, and will try and give it some love today.. Thanks for the LGTM.... |
…kageapi-to-jax-rs
…i/cluster/packages and errors.
|
@gerlowskija this is ready for review!!!! |
|
Tests, both unit and itest (bats) pass... |
|
@epugh I am planning to review this PR, can you make this one ready for review by rebasing with latest main? |
|
@jaykay12 I added you as a collaborate to my |
…n the Package v2 API - Move the inter-node refresh/sync fan-out off GET /cluster/packages (which was mutating state via refreshPackage/expectedVersion query params) onto POST endpoints: a localOnly flag on the existing /refresh action (mirroring ClusterFileStoreApis.deleteFile's localDelete), and a new /sync action. - getPackage() now returns 404 for an unknown package, matching deletePackageVersion/refreshPackage's existing NOT_FOUND behavior. - Split the single-package GET response into its own flat shape (GetPackageResponse) instead of reusing the list endpoint's map-shaped response filtered to one entry, and renamed both response classes to match the List<Resource>Response / Get<Resource>Response convention used elsewhere (aliases, cluster properties, schema fields). - Extracted the duplicated node-broadcast loop in ClusterPackage into a shared helper. - Documented the List/Get response-naming convention in dev-docs/apis-v2-conventions.adoc. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019kzScQszwRcG4S7kA5Pa8b
PackageManager's deploy --update and undeploy flows were still POSTing a
v1-style JSON command body ({"refresh": "name"}) to /api/cluster/packages,
left over from before the JAX-RS migration. The new endpoint doesn't accept
a body at all - it's POST /cluster/packages/{name}/refresh - so these calls
were silently broken against the migrated server. Switch both call sites to
the generated PackageApi.RefreshPackage client, matching how
DeletePackageVersion/AddPackageVersion were already migrated elsewhere in
this file. Removes the now-unused PackageUtils.PACKAGE_PATH constant.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019kzScQszwRcG4S7kA5Pa8b
…kage API shape testPayload()'s @EndPoint/@command fixture (path /cluster/package, an AddVersion bean with pkg/version/files) mirrored the now-deleted v1 Package API almost exactly, which reads as leftover Package API code rather than a generic framework test. Rename to /foos/FooVersion/myfoo so it's obviously just a test fixture. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019kzScQszwRcG4S7kA5Pa8b
ReferenceEquality flagged schemas[0] != schemas[1] as a likely mistake, but the test intentionally checks whether the core picked up a new IndexSchema instance after the package version bump - identity, not value equality, is what's being verified. Suppress with the same pattern used elsewhere in the codebase for intentional identity checks (SolrConfig.java, CachingDirectoryFactory.java). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019kzScQszwRcG4S7kA5Pa8b
…sterPackage addPackageVersion and deletePackageVersion each inlined the same "deserialize packages.json bytes, fall back to a fresh Packages on missing/invalid data, then copy()" block, and the same isEnabled()/BAD_REQUEST guard. Extracted both into PackageStore (parseForUpdate, requireEnabled) since they operate on PackageStore's own data/mapper, and call them from both atomicUpdate lambdas. Also noted, via a one-line comment, why PackageManager's undeploy refresh call site keeps a broader catch(Exception) than its sibling deploy call site (it still wraps a postJsonToSolr call that declares throws Exception). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019kzScQszwRcG4S7kA5Pa8b
|
@jaykay12 would love your review! I think this is ready for merging. |
| /** | ||
| * Holds package data loaded from ZooKeeper ({@code /solr/packages.json}) and manages ZK watchers. | ||
| */ | ||
| public class PackageStore { |
There was a problem hiding this comment.
this class is majorly (PackageAPI - {code no longer needed}), please correct me if i am wrong.
[suggestion] should we be splitting up PRs in those case, so that review stays easier & any unintentional change gets caught.
This PR could have been just pure migration & removal of deprecated stuff from PackageAPI class. In subsequent follow-up this renaming could have been attempted?
This is my pure thought, with this minor change, the PR size would have reduced by atleast 8-9 files.
| @Override | ||
| @PermissionName(PACKAGE_EDIT_PERM) | ||
| public SolrJerseyResponse addPackageVersion( | ||
| String packageName, AddPackageVersionRequestBody requestBody) { |
There was a problem hiding this comment.
should the core logic related to addVersion & deleteVersion be kept in PackageStore or PackageAPI for now (if earlier comment is chosen to be addressed)
that way, this class remains as thin adapter only.
| return response; | ||
| } | ||
|
|
||
| private void syncToVersion(PackageStore packageStore, int expectedVersion) { |
There was a problem hiding this comment.
should this be kept as package private function inside PackageStore?
[reason]
this function mutates - packageStore.pkgs, ideally we can keep that ownership from within packageStore? if this function moves inside packageStore, we can esure package.pkgs is private to that class & no one changes its state from outside other than its own functions.
| solrClient, PackageUtils.PACKAGE_PATH, "{\"refresh\": \"" + packageName + "\"}"); | ||
| } catch (Exception ex) { | ||
| new PackageApi.RefreshPackage(packageName).process(solrClient); | ||
| } catch (Exception ex) { // postJsonToSolr above declares a plain throws Exception |
There was a problem hiding this comment.
this code comment still valid?
| /** Response for the get-a-specific-package API. */ | ||
| public class GetPackageResponse extends SolrJerseyResponse { | ||
|
|
||
| @JsonProperty("result") |
There was a problem hiding this comment.
[info] why the key name as "result", why not just "packageInfo" here?
| /** Response for the package listing API. */ | ||
| public class ListPackagesResponse extends SolrJerseyResponse { | ||
|
|
||
| @JsonProperty("result") |
There was a problem hiding this comment.
[question] why not "packages" as the key?
| @JsonProperty(required = true) | ||
| public List<String> files; | ||
| @JsonProperty("version") | ||
| @Schema(description = "The version string for this package version.", required = true) |
There was a problem hiding this comment.
thanks, going to look....

Migrates
org.apache.solr.pkg.PackageAPIfrom Solr's homegrown@EndPoint/@Commanddispatch to standard JAX-RS annotations, consistent with other V2 APIs (ClusterFileStore,ZookeeperRead,ClusterProperty).This has a pretty hefty update to the patterns, but I thought it was better to do it now while v2 api's are "experimental".
New REST endpoints
The command-based POST pattern is replaced with RESTful routes. Note the collection is now plural (
/cluster/packages), matching the v2 API path conventions used elsewhere:GET /cluster/packageGET /cluster/packagesGET /cluster/package/{name}GET /cluster/packages/{name}(now returns 404 if the package doesn't exist, instead of silently returning an empty result)POST /cluster/package {"add": {"package":"p","version":"v","files":[...]}}POST /cluster/packages/{name}/versionsPOST /cluster/package {"delete": {"pkg":"p","version":"v"}}DELETE /cluster/packages/{name}/versions/{version}POST /cluster/package {"refresh": "name"}POST /cluster/packages/{name}/refreshrefreshfor node-local reload)POST /cluster/packages/{name}/refresh?localOnly=truePOST /cluster/packages/sync?expectedVersion=NThe two internal-only rows replace an earlier version of this PR that smuggled the same inter-node signals onto
GET /cluster/packagesviarefreshPackage/expectedVersionquery params — a GET request shouldn't have side effects.localOnlymirrors the existinglocalDeleteparam onClusterFileStoreApis.deleteFile.Key structural changes
PackageAPI— new JAX-RS implementation (extends JerseyResource implements PackageApis); replaces the oldEdit/Readinner classes (~220 lines removed)PackageStore— renamed from the oldPackageAPI; now clearly a ZK data/state holder (Packages,PkgVersion, ZK watcher), not an endpoint class. THIS WAS A BIG REFACTORINGsolr/apimodule — newPackageApis.java(JAX-RS interface),AddPackageVersionRequestBody.java, and two response types instead of one:ListPackagesResponse(theGET /cluster/packagescollection response, map-keyed by package name) andGetPackageResponse(theGET /cluster/packages/{name}single-resource response, a flat object for just that package) — matching theList<Resource>Response/Get<Resource>Responsenaming and shape convention used byListAliasesResponse/GetAliasByNameResponseand similar pairs elsewhere in the v2 API. OAS generation producesPackageApiSolrJ request classes automatically.PackageAPITest— integration test usingSolrCloudTestCase(ZK required) with generatedPackageApiSolrJ request classesTestPackages— updated to use new endpoints; error path changed from/details[0]/errorMessages[0]to/msgpackage-manager-internals.adoc— updated endpoint reference and curl examplesdev-docs/apis-v2-conventions.adoc— added a new "Listing vs. Single-Resource Responses" section documenting theList<Resource>Response/Get<Resource>Responseconvention, since this PR is the first to need it spelled out explicitly